/*     */ package com.zimbra.soap;
/*     */ 
/*     */ import com.google.common.base.Charsets;
/*     */ import com.google.common.base.Function;
/*     */ import com.google.common.collect.MapMaker;
/*     */ import com.zimbra.common.auth.ZAuthToken;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.soap.Element;
/*     */ import com.zimbra.common.soap.SoapProtocol;
/*     */ import com.zimbra.common.stats.StopWatch;
/*     */ import com.zimbra.common.util.BufferStream;
/*     */ import com.zimbra.common.util.ByteUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import com.zimbra.common.util.RemoteIP;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.common.util.ZimbraServletOutputStream;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.servlet.ZimbraServlet;
/*     */ import com.zimbra.cs.stats.ZimbraPerf;
/*     */ import com.zimbra.cs.util.Zimbra;
/*     */ import java.io.EOFException;
/*     */ import java.io.IOException;
/*     */ import java.util.ArrayList;
/*     */ import java.util.HashMap;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import javax.servlet.ServletException;
/*     */ import javax.servlet.ServletOutputStream;
/*     */ import javax.servlet.UnavailableException;
/*     */ import javax.servlet.http.HttpServletRequest;
/*     */ import javax.servlet.http.HttpServletResponse;
/*     */ import org.apache.commons.httpclient.HttpVersion;
/*     */ import org.apache.commons.httpclient.ProtocolException;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class SoapServlet
/*     */   extends ZimbraServlet
/*     */ {
/*     */   private static final long serialVersionUID = 38710345271877593L;
/*     */   protected static final String PARAM_ENGINE_HANDLER = "engine.handler.";
/*     */   public static final String ZIMBRA_AUTH_TOKEN = "zimbra.authToken";
/*     */   public static final String SERVLET_CONTEXT = "servlet.context";
/*     */   public static final String SERVLET_REQUEST = "servlet.request";
/*     */   public static final String SERVLET_RESPONSE = "servlet.response";
/*     */   public static final String IS_ADMIN_REQUEST = "zimbra.isadminreq";
/*     */   public static final String INVALIDATE_COOKIES = "zimbra.invalidateCookies";
/*     */   
/*     */   private static class ArrayListFactory
/*     */     implements Function<String, List<DocumentService>>
/*     */   {
/*     */     public List<DocumentService> apply(String from)
/*     */     {
/*  81 */       return new ArrayList();
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*  88 */   private static Map<String, List<DocumentService>> sExtraServices = new MapMaker().makeComputingMap(new ArrayListFactory(null));
/*     */   
/*     */ 
/*  91 */   private static Log sLog = LogFactory.getLog(SoapServlet.class);
/*     */   private SoapEngine mEngine;
/*     */   
/*     */   public void init() throws ServletException
/*     */   {
/*  96 */     LogFactory.init();
/*     */     
/*  98 */     String name = getServletName();
/*  99 */     ZimbraLog.soap.info("Servlet " + name + " starting up");
/* 100 */     super.init();
/*     */     
/* 102 */     this.mEngine = new SoapEngine();
/*     */     
/* 104 */     int i = 0;
/*     */     String cname;
/* 106 */     while ((cname = getInitParameter("engine.handler." + i)) != null) {
/* 107 */       loadHandler(cname);
/* 108 */       i++;
/*     */     }
/*     */     
/*     */ 
/* 112 */     synchronized (sExtraServices) {
/* 113 */       List<DocumentService> services = (List)sExtraServices.get(getServletName());
/* 114 */       for (DocumentService service : services) {
/* 115 */         addService(service);
/* 116 */         i++;
/*     */       }
/*     */     }
/*     */     
/* 120 */     this.mEngine.getDocumentDispatcher().clearSoapWhiteList();
/*     */     
/* 122 */     if (i == 0) {
/* 123 */       throw new ServletException("Must specify at least one handler engine.handler." + i);
/*     */     }
/*     */     try {
/* 126 */       Zimbra.startup();
/*     */     } catch (OutOfMemoryError e) {
/* 128 */       Zimbra.halt("out of memory", e);
/*     */     } catch (Throwable t) {
/* 130 */       ZimbraLog.soap.fatal("Unable to start servlet", t);
/* 131 */       throw new UnavailableException(t.getMessage());
/*     */     }
/*     */   }
/*     */   
/*     */   public void destroy() {
/* 136 */     String name = getServletName();
/* 137 */     ZimbraLog.soap.info("Servlet " + name + " shutting down");
/*     */     try {
/* 139 */       Zimbra.shutdown();
/*     */     }
/*     */     catch (ServiceException e) {
/* 142 */       ZimbraLog.soap.error("ServiceException while shutting down servlet " + name, e);
/*     */     } catch (RuntimeException e) {
/* 144 */       ZimbraLog.soap.error("Unchecked Exception while shutting down servlet " + name, e);
/* 145 */       throw e;
/*     */     }
/*     */     
/*     */ 
/* 149 */     this.mEngine = null;
/*     */     
/* 151 */     super.destroy();
/*     */   }
/*     */   
/*     */   private void loadHandler(String cname) throws ServletException {
/* 155 */     Class<?> dispatcherClass = null;
/*     */     try {
/* 157 */       dispatcherClass = Class.forName(cname);
/*     */     } catch (ClassNotFoundException cnfe) {
/* 159 */       throw new ServletException("can't find handler initializer class " + cname, cnfe);
/*     */     } catch (OutOfMemoryError e) {
/* 161 */       Zimbra.halt("out of memory", e);
/*     */     } catch (Throwable t) {
/* 163 */       throw new ServletException("can't find handler initializer class " + cname, t);
/*     */     }
/*     */     
/*     */     Object dispatcher;
/*     */     try
/*     */     {
/* 169 */       dispatcher = dispatcherClass.newInstance();
/*     */     } catch (InstantiationException ie) {
/* 171 */       throw new ServletException("can't instantiate class " + cname, ie);
/*     */     } catch (IllegalAccessException iae) {
/* 173 */       throw new ServletException("can't instantiate class " + cname, iae);
/*     */     }
/*     */     
/* 176 */     if (!(dispatcher instanceof DocumentService)) {
/* 177 */       throw new ServletException("class not an instanceof HandlerInitializer: " + cname);
/*     */     }
/*     */     
/* 180 */     DocumentService hi = (DocumentService)dispatcher;
/* 181 */     addService(hi);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void addService(String servletName, DocumentService service)
/*     */   {
/* 190 */     synchronized (sExtraServices) {
/* 191 */       ZimbraServlet servlet = ZimbraServlet.getServlet(servletName);
/* 192 */       if (servlet != null) {
/* 193 */         ((SoapServlet)servlet).addService(service);
/*     */       } else {
/* 195 */         sLog.debug("addService(%s, %s): servlet has not been initialized", new Object[] { servletName, service.getClass().getSimpleName() });
/*     */         
/* 197 */         List<DocumentService> services = (List)sExtraServices.get(servletName);
/* 198 */         services.add(service);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void addService(DocumentService service) {
/* 204 */     ZimbraLog.soap.info("Adding service %s to %s", new Object[] { service.getClass().getSimpleName(), getServletName() });
/* 205 */     service.registerHandlers(this.mEngine.getDocumentDispatcher());
/*     */   }
/*     */   
/*     */   public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
/* 209 */     ZimbraLog.clearContext();
/* 210 */     long startTime = ZimbraPerf.STOPWATCH_SOAP.start();
/*     */     try
/*     */     {
/* 213 */       doWork(req, resp);
/*     */     } finally {
/* 215 */       ZimbraLog.clearContext();
/* 216 */       ZimbraPerf.STOPWATCH_SOAP.stop(startTime);
/*     */     }
/*     */   }
/*     */   
/*     */   private void doWork(HttpServletRequest req, HttpServletResponse resp) throws IOException {
/* 221 */     int len = req.getContentLength();
/*     */     
/* 223 */     boolean isResumed = true;
/*     */     
/*     */ 
/*     */ 
/*     */ 
/* 228 */     byte[] buffer = (byte[])req.getAttribute("com.zimbra.request.buffer");
/* 229 */     if (buffer == null) {
/* 230 */       isResumed = false;
/*     */       
/*     */ 
/* 233 */       int maxSize = 0;
/*     */       try {
/* 235 */         maxSize = Provisioning.getInstance().getLocalServer().getIntAttr("zimbraSoapRequestMaxSize", 0);
/*     */       } catch (ServiceException e) {
/* 237 */         ZimbraLog.soap.warn("Unable to look up %s.  Not limiting the request size.", "zimbraSoapRequestMaxSize", e);
/*     */       }
/* 239 */       if (maxSize <= 0) {
/* 240 */         maxSize = Integer.MAX_VALUE;
/*     */       }
/*     */       
/*     */       boolean success;
/*     */       boolean success;
/* 245 */       if (len > maxSize) {
/* 246 */         success = false;
/*     */       } else {
/* 248 */         BufferStream bs = null;
/*     */         try
/*     */         {
/* 251 */           bs = new BufferStream(len, maxSize, maxSize);
/* 252 */           int in = (int)bs.readFrom(req.getInputStream(), len >= 0 ? len : 2147483647L);
/*     */           
/*     */ 
/* 255 */           if ((len > 0) && (in < len))
/* 256 */             throw new EOFException("SOAP content truncated " + in + "!=" + len);
/* 257 */           success = in <= maxSize;
/* 258 */           buffer = bs.toByteArray();
/*     */         } finally {
/* 260 */           ByteUtil.closeStream(bs);
/*     */         }
/*     */       }
/*     */       
/*     */ 
/* 265 */       if (!success) {
/* 266 */         String sizeString = " size " + len;
/* 267 */         String msg = String.format("Request%s exceeded limit of %d bytes set for %s.", new Object[] { sizeString, Integer.valueOf(maxSize), "zimbraSoapRequestMaxSize" });
/*     */         
/* 269 */         ServiceException e = ServiceException.INVALID_REQUEST(msg, null);
/* 270 */         ZimbraLog.soap.warn(null, e);
/* 271 */         Element fault = SoapProtocol.Soap12.soapFault(e);
/* 272 */         Element envelope = SoapProtocol.Soap12.soapEnvelope(fault);
/* 273 */         sendResponse(req, resp, envelope);
/* 274 */         return;
/*     */       }
/*     */       
/* 277 */       req.setAttribute("com.zimbra.request.buffer", buffer);
/*     */     }
/*     */     
/* 280 */     HashMap<String, Object> context = new HashMap();
/* 281 */     context.put("servlet.context", getServletContext());
/* 282 */     context.put("servlet.request", req);
/* 283 */     context.put("servlet.response", resp);
/*     */     try
/*     */     {
/* 286 */       Boolean isAdminReq = Boolean.valueOf(isAdminRequest(req));
/* 287 */       context.put("zimbra.isadminreq", isAdminReq);
/*     */     } catch (ServiceException se) {
/* 289 */       ZimbraLog.soap.warn("unable to determine isAdminReq", se);
/*     */     }
/*     */     
/*     */ 
/* 293 */     RemoteIP remoteIp = new RemoteIP(req, ZimbraServlet.getTrustedIPs());
/* 294 */     context.put("soap.request.ip", remoteIp.getClientIP());
/* 295 */     context.put("orig.request.ip", remoteIp.getOrigIP());
/* 296 */     context.put("request.ip", remoteIp.getRequestIP());
/* 297 */     remoteIp.addToLoggingContext();
/*     */     
/*     */ 
/*     */ 
/* 301 */     Element envelope = null;
/*     */     try {
/* 303 */       envelope = this.mEngine.dispatch(req.getRequestURI(), buffer, context);
/* 304 */       if (context.containsKey("zimbra.invalidateCookies")) {
/* 305 */         ZAuthToken.clearCookies(resp);
/*     */       }
/*     */     } catch (Throwable e) {
/* 308 */       if ((e instanceof OutOfMemoryError)) {
/* 309 */         Zimbra.halt("handler exception", e);
/*     */       }
/*     */       
/* 312 */       if ((ZimbraLog.soap.isTraceEnabled()) && (!context.containsKey("soap.request.logged"))) {
/* 313 */         ZimbraLog.soap.trace(!isResumed ? "C:\n%s" : "C: (resumed)\n%s", new Object[] { new String(buffer, Charsets.UTF_8) });
/*     */       }
/*     */       
/*     */ 
/* 317 */       if (e.getClass().getName().equals("org.eclipse.jetty.continuation.ContinuationThrowable")) {
/* 318 */         throw ((Error)e);
/*     */       }
/* 320 */       ZimbraLog.soap.warn("handler exception", e);
/* 321 */       Element fault = SoapProtocol.Soap12.soapFault(ServiceException.FAILURE(e.toString(), e));
/* 322 */       envelope = SoapProtocol.Soap12.soapEnvelope(fault);
/*     */     }
/*     */     
/* 325 */     if (ZimbraLog.soap.isTraceEnabled()) {
/* 326 */       ZimbraLog.soap.trace("S:\n%s", new Object[] { envelope.prettyPrint() });
/*     */     }
/* 328 */     sendResponse(req, resp, envelope);
/*     */   }
/*     */   
/*     */   private int soapResponseBufferSize() {
/* 332 */     String val = LC.soap_response_buffer_size.value();
/* 333 */     if ((val == null) || (val.length() == 0)) {
/* 334 */       return -1;
/*     */     }
/* 336 */     return LC.soap_response_buffer_size.intValue();
/*     */   }
/*     */   
/*     */   private void sendResponse(HttpServletRequest req, HttpServletResponse resp, Element envelope) throws IOException {
/* 340 */     SoapProtocol soapProto = SoapProtocol.determineProtocol(envelope);
/* 341 */     int statusCode = soapProto.hasFault(envelope) ? 500 : 200;
/*     */     
/*     */ 
/* 344 */     boolean chunkingEnabled = LC.soap_response_chunked_transfer_encoding_enabled.booleanValue();
/*     */     
/* 346 */     if (chunkingEnabled)
/*     */     {
/* 348 */       String proto = req.getProtocol();
/*     */       try {
/* 350 */         HttpVersion httpVer = HttpVersion.parse(proto);
/* 351 */         chunkingEnabled = !httpVer.lessEquals(HttpVersion.HTTP_1_0);
/*     */       } catch (ProtocolException e) {
/* 353 */         ZimbraLog.soap.warn("cannot parse http version in request: %s, http chunked transfer encoding disabled", proto, e);
/*     */         
/* 355 */         chunkingEnabled = false;
/*     */       }
/*     */     }
/*     */     
/*     */ 
/* 360 */     int responseBufferSize = soapResponseBufferSize();
/* 361 */     if (responseBufferSize != -1) {
/* 362 */       resp.setBufferSize(responseBufferSize);
/*     */     }
/* 364 */     resp.setContentType(soapProto.getContentType());
/* 365 */     resp.setStatus(statusCode);
/* 366 */     resp.setHeader("Cache-Control", "no-store, no-cache");
/*     */     
/* 368 */     if (chunkingEnabled)
/*     */     {
/* 370 */       ZimbraServletOutputStream out = new ZimbraServletOutputStream(resp.getOutputStream());
/* 371 */       envelope.output(out);
/* 372 */       out.flush();
/*     */     }
/*     */     else {
/* 375 */       byte[] soapBytes = envelope.toUTF8();
/* 376 */       resp.setContentLength(soapBytes.length);
/* 377 */       resp.getOutputStream().write(soapBytes);
/* 378 */       resp.getOutputStream().flush();
/*     */     }
/* 380 */     envelope.destroy();
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/soap/SoapServlet.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */